﻿using UnityEngine;
using System.Collections;

public class Enemy : Character
{
	public enum EnemyState
	{
		SPAWN = 0,
		WANDER,
		PLAYERINRANGE,
		COUNT
	}

	public enum EnemyType
	{
		SMALLSPIDER = 0,
		BIGSPIDER,
		THUG,
		COUNT
	}

	public EnemyType m_Type;

	public Collider2D m_HitDetection;
	public ColliderSendMessage m_ViewRange;
	
	public float m_MinChooseNewTargetDelay = 0.5f;
	public float m_MaxChooseNewTargetDelay = 2.5f;
	public float m_DistanceWithPlayerThreshold = 0.5f;
	public float m_YAxisHitDetectionThreshold = 0.1f;
	public float m_MinimumVelocityY = 1.5f;
	public float m_AutoKillDelay = 3f;
	public float m_MinDistanceWander = 0.5f;

	[HideInInspector]
	public LevelPartInfo m_LevelOwner;
	[HideInInspector]
	public bool m_AutoKill = false;

	protected Vector3 m_InitialIdlePosition;
	protected EnemyState m_CurrentState;

	protected bool m_ReachedTargetX = false;
	protected bool m_ReachedTargetY = false;

	private float m_AutoKillTimer;

	// WANDER VARIABLES
	private bool m_ChooseNewTarget = true; 
	private bool m_TargetReached = false; 

	protected virtual void Start () 
	{
		if(m_ViewRange != null) m_ViewRange.m_OnTriggerEnter2D += OnPlayerInRange;

		//TODO Assign this value not in the start, but when the enemy appears in screen from spawner and has reached its idle position
		m_CurrentState = EnemyState.SPAWN;
	}

	protected override void Update ()
	{
		base.Update();
		
		m_HighestSpeed = Mathf.Abs(m_Rigidbody2D.velocity.x) > Mathf.Abs(m_Rigidbody2D.velocity.y) ? Mathf.Abs(m_Rigidbody2D.velocity.x) : Mathf.Abs(m_Rigidbody2D.velocity.y);
		m_Animator.speed = m_HighestSpeed * m_AnimSpeedModifier;
		
		// TODO Check the z effect that feels right
		// SUGGESTION: Have a transform to determine the good y and z
		//SetZIndex(aTransform.position.y);
		SetZIndex(m_ShadowRenderer.bounds.center.y);

		CheckDirection();
		
		if(m_IsHurt)
		{
			m_NewColor = m_SpriteRenderer.color;
			m_NewColor.a = m_NewAlphaReacher.CurrentValue;
			m_SpriteRenderer.color = m_NewColor;
		}

		if(m_AutoKill)
		{
			if(m_SpriteRenderer.bounds.max.x < RefManager.GameplayCamera.LeftLimit)
			{
				m_AutoKillTimer += Time.deltaTime;

				if(m_AutoKillTimer > m_AutoKillDelay)
				{
					OnDead();
				}
			}
			else
			{
				m_AutoKillTimer = 0;
			}
		}
		
		Debug.DrawRay(m_SizeCollider.bounds.min, (Vector3)(m_Rigidbody2D.velocity.normalized) * 10f, Color.cyan);
	}

	protected virtual void CheckDirection()
	{
		switch(m_CurrentState)
		{
		case EnemyState.SPAWN:
			if(m_Rigidbody2D.velocity.x != 0) m_Direction = m_Rigidbody2D.velocity.x > 0 ? Character.Direction.RIGHT : Character.Direction.LEFT;
			if(!m_TargetReached)
			{
				MoveToTarget (m_NewTarget, m_TargetDirection, m_HorizontalWalkingSpeed, m_VerticalWalkingSpeed, OnTargetReached);
			}
			break;
		case EnemyState.WANDER:
			if(m_Rigidbody2D.velocity.x != 0) m_Direction = m_Rigidbody2D.velocity.x > 0 ? Character.Direction.RIGHT : Character.Direction.LEFT;
			Wander();
			break;
		case EnemyState.PLAYERINRANGE:
			if(RefManager.Instance.Player1.aTransform.position.x < aTransform.position.x)
			{
				m_Direction = Character.Direction.LEFT;
			}
			else
			{
				m_Direction = Character.Direction.RIGHT;
			}
			FollowPlayer();
			break;
		}
		
		if(m_ReachedTargetX && m_ReachedTargetY)
		{
			m_HitDetection.enabled = true;
		}
		else
		{
			m_HitDetection.enabled = false;
		}
		
		if(m_PreviousDirection != m_Direction)
		{
			FlipSprite();
		}
		
		m_PreviousDirection = m_Direction;
	}

	#region GENERIC AI
	private void FollowPlayer()
	{		
		// TODO Maybe check this every 0.5f seconds for performance
		if((Vector3.Distance(RefManager.Instance.Player1.aTransform.position, aTransform.position) <= Size.x/2f + RefManager.Instance.Player1.Size.x + m_DistanceWithPlayerThreshold))
		{			
			m_ReachedTargetX = true;
			
			if(Mathf.Abs(RefManager.Instance.Player1.m_SizeCollider.bounds.min.y - m_SizeCollider.bounds.min.y) <= m_YAxisHitDetectionThreshold)
			{
				m_ReachedTargetY = true;
				Move (0, 0);
			}
			else
			{
				m_ReachedTargetY = false;
				m_TargetDirection = (RefManager.Instance.Player1.m_SizeCollider.bounds.min - m_SizeCollider.bounds.min).normalized;
				Move (m_TargetDirection, 0, m_VerticalWalkingSpeed, m_MinimumVelocityY);
			}
		}
		else
		{
			m_ReachedTargetX = false;
			m_ReachedTargetY = false;
			
			m_TargetDirection = (RefManager.Instance.Player1.m_SizeCollider.bounds.min - m_SizeCollider.bounds.min).normalized;
			Move (m_TargetDirection, m_HorizontalWalkingSpeed, m_VerticalWalkingSpeed);
		}
	}
	
	private void Wander()
	{
		if(m_ChooseNewTarget)
		{
			m_ChooseNewTarget = false;
			m_TargetReached = false;
			m_NewTarget = m_InitialIdlePosition;
			//newTarget.x += 0.1f;
			m_NewTarget.x += Random.Range(-m_MinDistanceWander, m_MinDistanceWander);
			m_NewTarget.y += Random.Range(-m_MinDistanceWander, m_MinDistanceWander);
			m_TargetDirection = (m_NewTarget - aTransform.position).normalized;
		}
		else
		{
			if(!m_TargetReached)
			{
				MoveToTarget (m_NewTarget, m_TargetDirection, m_HorizontalWalkingSpeed, m_VerticalWalkingSpeed, OnTargetReached);
			}
		}
	}
	
	private void OnTargetReached()
	{
		m_TargetReached = true;
		switch(m_CurrentState)
		{
		case EnemyState.SPAWN:
			m_CurrentState = EnemyState.WANDER;			
			m_InitialIdlePosition = aTransform.position;
			break;
		case EnemyState.WANDER:
			Invoke ("ResetNewTarget", Random.Range(m_MinChooseNewTargetDelay, m_MaxChooseNewTargetDelay));
			break;
		}
	}
	
	private void ResetNewTarget()
	{
		m_ChooseNewTarget = true;
	}
	protected virtual void OnPlayerInRange(Collider2D i_Collider)
	{
		if(i_Collider.tag == "PlayerSize")
		{
			m_CurrentState = EnemyState.PLAYERINRANGE;
		}
	}
	#endregion

	#region HURT
	protected virtual void OnHit(float i_Value)
	{
		Hurt (i_Value);
	}

	protected override void Hurt(float i_Value)
	{
		base.Hurt(i_Value);
		
		if(m_NewAlphaReacher == null)
		{
			m_NewAlphaReacher = aGameObject.AddComponent<ValueReacher>();
		}
		else
		{
			m_NewAlphaReacher.Reset();
		}
		m_NewAlphaReacher.SetupValues(1f, 0f, m_HurtDuration/2f, true, false);
		
		m_NewAlphaReacher.m_OnFinish += OnHurtFinished;
	}

	protected override void OnHurtFinished ()
	{
		base.OnHurtFinished ();
		
		m_NewColor = m_SpriteRenderer.color;
		m_NewColor.a = m_NewAlphaReacher.CurrentValue;
		m_SpriteRenderer.color = m_NewColor;
	}

	protected override void OnDead()
	{
		EnemyManager.Instance.UnregisterEnemyPerLevel(m_LevelOwner);

		base.OnDead();
	}
	#endregion
}
